/*
 * -----------------------------------------------------------------------------
 * Project    : Memory Support
 * Purpose    : Provide support for memory allocation of objects
 * File       : Win32.MemoryObject.cpp
 * Author     : Eduardo Sobrino
 * Date       : Nov/98
 * LastUpdate : Jun/2k6 (Revice code from previous version)
 */

#pragma region   // Include Files

#include "stdafx.h"
#include "Win32.MemoryObject.h"

#pragma endregion

// -----------------------------------------------------------------------------

namespace Kif
{
namespace Win32
{

// -----------------------------------------------------------------------------

#pragma region // Define MemoryObject

/// <summary>allocate parameter</summary>
/// <param name="type">type of object to allocate</param>
/// <param name="size">size of object to allocate</param>
/// <param name="disposable">true if we are responsable for it's disposition.
/// This mostly apply to Blob's since is likely that some other process will
/// allocate for it's resources and will be the responsable for it's memory
/// management and disposition...</param>
/// <remarks>if the given type does not exists this constructure will throw
/// an exception...</remarks>
MemoryObject::MemoryObject(
   Kif::Win32::BaseType type, DWORD size, bool disposable)
{
   this->type = type;
   this->disposable = disposable;
   switch(type)
   {
      case Kif::Win32::BaseType_Boolean:
         memBuffer.Alloc(sizeof(short));
         break;
      case Kif::Win32::BaseType_Int16:
         memBuffer.Alloc(sizeof(short));
         break;
      case Kif::Win32::BaseType_Int32:
         memBuffer.Alloc(sizeof(long));
         break;
      case Kif::Win32::BaseType_Float:
         memBuffer.Alloc(sizeof(double));
         break;
      case Kif::Win32::BaseType_Double:
         memBuffer.Alloc(sizeof(double));
         break;
      case Kif::Win32::BaseType_AnsiString:
         if (size == 0)
            size = MaxSize;
         memBuffer.Alloc(sizeof(char)*(size+1));
         if (memBuffer.Buffer)
            *memBuffer.Buffer = NULL;
         break;
      case Kif::Win32::BaseType_WideString:
         if (size <= 0)
            size = MaxSize;
         memBuffer.Alloc(sizeof(wchar_t)*(size+1));
         if (memBuffer.Buffer)
            *memBuffer.Buffer = NULL;
         break;
      case Kif::Win32::BaseType_DateTime:
         memBuffer.Alloc(sizeof(TIMESTAMP_STRUCT));
         break;
      case Kif::Win32::BaseType_Blob:
         // allocate for Blob's only if we are responsable for it's
         // disposition...
         if (disposable)
            memBuffer.Alloc(sizeof(BYTE)*size);
         break;
      default:
         throw _T("MemoryObject::Unsupported Type");
   }
}  // end of MemoryObject

/// <summary>set inner value</summary>
void MemoryObject::setValue(void *value, Kif::Win32::BaseType type, DWORD size)
{
   if (value == NULL)
      return;

   switch(this->type)
   {
      case Kif::Win32::BaseType_Int16:
         {
            short *s = (short*)memBuffer.Buffer;
            *s = (short)*((short*)value);
         }
         break;
      case Kif::Win32::BaseType_Int32:
         {
            long *l = (long*)memBuffer.Buffer;
            *l = (long)*((long*)value);
         }
         break;
      case Kif::Win32::BaseType_Float:
         {
            float *l = (float*)memBuffer.Buffer;
            *l = (float)*((double*)value);
         }
         break;
      case Kif::Win32::BaseType_Double:
         {
            double *l = (double*)memBuffer.Buffer;
            *l = (double)*((double*)value);
         }
         break;
      case Kif::Win32::BaseType_AnsiString:
         {
            DWORD bsize;
            char *v = (char*)value;
            if (memBuffer.Buffer == NULL)
            {
               DWORD szInBytes = sizeof(char) * (size+1);
               memBuffer.Alloc(szInBytes);
               bsize = size;
            }
            else
               bsize = (DWORD)((memBuffer.GetSize()/sizeof(char))-1);

            if (bsize < 0)
               bsize = 0;
            if (size > bsize)
               size = bsize;

            char *s = (char*)memBuffer.Buffer;
            Kif::Win32::Memory::copy<char>(s,bsize,v,size);
            *(s + size) = NULL;
         }
         break;
      case Kif::Win32::BaseType_WideString:
         {
            DWORD bsize;
            TCHAR *v = (TCHAR*)value;
            DWORD  vLen = Kif::Win32::String::GetLength(v);

            if (memBuffer.Buffer == NULL)
            {
               DWORD szInBytes = sizeof(TCHAR) * (size+1);
               memBuffer.Alloc(szInBytes);
               bsize = size;
            }
            else
               bsize = (DWORD)((memBuffer.GetSize()/sizeof(TCHAR))-1);

            if (bsize < 0)
               bsize = 0;
            if (vLen > bsize)
               vLen = bsize;

            TCHAR *s = (TCHAR*)memBuffer.Buffer;
            if (vLen > 0)
               Kif::Win32::Memory::copy<TCHAR>(s,bsize,v,vLen);
            *(s + vLen) = NULL;
         }
         break;
      case Kif::Win32::BaseType_DateTime:
         {
            TIMESTAMP_STRUCT *v = (TIMESTAMP_STRUCT*)value;
            TIMESTAMP_STRUCT *s = (TIMESTAMP_STRUCT*)memBuffer.Buffer;
            *s = *v;
         }
         break;
      case Kif::Win32::BaseType_Blob:
         if (disposable)
            Kif::Win32::Memory::copy<BYTE>(
               memBuffer.Buffer,memBuffer.GetSizeInBytes(),(BYTE*)value,size);
         else
            memBuffer.SetBuffer((BYTE*)value,size,disposable);
         break;
      default:
         throw _T("MemoryObject::setValue: Invalid type assignment");
         break;
   }
}  // end of setValue

/// <summary>Check if types are co</summary>
Kif::Win32::ObjectCompatibility
   MemoryObject::Compatible(Kif::Win32::BaseType type,DWORD size)
{
   ObjectCompatibility c = Kif::Win32::Object_Incompatible;
   if (IsNumeric(type) == IsNumeric())
   {
      DWORD sz = SizeOfType(type);
      if (IsInteger(type) == IsInteger())
      {
         c = (sz <= SizeOfType()) ?
            Kif::Win32::Object_Compatible :
            Kif::Win32::Object_LossOfPrecision;
      }
      else
      if (IsFloat(type) == IsFloat())
      {
         c = (sz <= SizeOfType()) ?
            Kif::Win32::Object_Compatible :
            Kif::Win32::Object_LossOfPrecision;
      }
   }
   else
   if (IsString(type) == IsString())
   {
      size_t l = memBuffer.GetSize();
      c = (l <= size) ?
         Kif::Win32::Object_Compatible :
         Kif::Win32::Object_WillBeTruncated;
   }
   else
   if (IsDateTime(type) == IsDateTime())
      c = Kif::Win32::Object_Compatible;
   else
   if (IsBlob(type) == IsBlob())
   {
      size_t l = memBuffer.GetSize();
      c = (l <= size) ?
         Kif::Win32::Object_Compatible :
         Kif::Win32::Object_WillBeTruncated;
   }

   return(c);
}  // end of Compatible

#pragma endregion // end of MemoryObject

}
}
